package com.crazy.web.config.redis;

import com.crazy.web.receivers.BaseReceiver;
import com.crazy.web.receivers.Receiver1;
import org.reflections.Reflections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.lang.reflect.InvocationTargetException;
import java.util.Set;

/**
 * @author zhaochaofeng
 * @version 1.0
 * @date 2021/1/6 10:23
 */
@Configuration
@EnableCaching
public class RedisConfig {

    @Autowired
    private ConfigurableApplicationContext context;
    @Autowired
    private ApplicationContext applicationContext;

    //默认的监听方法
    private final String defaultListenerMethod = "receiveMessage";

    @Bean
    public RedisTemplate<Object, Object> MyRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        // 设置其他的k-v的默认的序列化
        template.setDefaultSerializer(new Jackson2JsonRedisSerializer(Object.class));
        //单独设置k的序列化
        template.setKeySerializer(new StringRedisSerializer());

        return template;
    }

    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);

        Reflections reflections = new Reflections(BaseReceiver.class.getPackage().getName());
        Set<Class<? extends BaseReceiver>> receiversClass = reflections.getSubTypesOf(BaseReceiver.class);
        //计数
        int count = 1;
        for (Class<? extends BaseReceiver> receiverClass : receiversClass) {
            //将MessageListenerAdapter的对象注册到容器，否则会出现空指针异常
            BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) context.getBeanFactory();
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MessageListenerAdapter.class);
            //定义参数
            BaseReceiver receiver = receiverClass.newInstance();
            builder.addPropertyValue("delegate", receiver).addPropertyValue("defaultListenerMethod", defaultListenerMethod);
            beanFactory.registerBeanDefinition("listenerAdapter"+count, builder.getRawBeanDefinition());
            container.addMessageListener((MessageListenerAdapter) applicationContext.getBean("listenerAdapter"+count), new PatternTopic(
                    (String) receiverClass.getMethod("getChannel").invoke(receiver)));
            count++;
        }

        container.addMessageListener(new MessageListenerAdapter(new Receiver1(), "receiveMessage"), new PatternTopic("channel-1"));
        return container;
    }


    /**
     * 绑定消息监听者和接收监听的方法,必须要注入这个监听器，不然会报错
     */
    @Bean
    public MessageListenerAdapter listenerAdapter() {
        return new MessageListenerAdapter(new Receiver1(), "receiveMessage");
    }
}
